package anatex.semantics;

import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.persistence.TypedQuery;

import anatex.domain.Category;
import anatex.domain.Document;
import anatex.domain.DocumentCategory;
import anatex.domain.DocumentRelatedDocument;
import anatex.domain.Keyword;
import anatex.domain.KeywordDocument;

public class RelatedDocumentsFinder {
	
	public static final int WEIGHT_FROM_KEYWORD = 2;
	public static final int WEIGHT_FROM_CATEGORY = 4;
	
	protected DocumentRelatedDocument lastRelationFound = null;
	
	protected Boolean doesRelationExist (Document document, Document relatedDocument) {
		try {
			lastRelationFound = DocumentRelatedDocument.findDocumentRelatedDocumentsByDocumentAndRelatedDocument(document, relatedDocument).getSingleResult();
		} catch (Exception ex) {
			lastRelationFound = null;
			
			return false;
		}
		
		return true;
	}
	
	public void findAndLog (Document document) {
		HashMap<String, Document> relatedDocuments = new HashMap<String, Document>();
		HashMap<String, Integer> relatedDocumentsWeights = new HashMap<String, Integer>();
		
		//find related documents based on related keywords 
		try {
			List<KeywordDocument> relatedKeywords = KeywordDocument.findKeywordDocumentsByDocument(document).getResultList();
			
			for (KeywordDocument kd : relatedKeywords) {
				Keyword keyword = kd.getKeyword();
				List<KeywordDocument> rDocs = KeywordDocument.findKeywordDocumentsByKeyword(keyword).getResultList();
				
				for (KeywordDocument kwd : rDocs) {
					if (kwd.getDocument().getId() == document.getId()) {
						continue;
					}
					
					String dId = kwd.getDocument().getId().toString();
					
					if (! relatedDocuments.containsKey(dId)) {
						relatedDocuments.put(dId, kwd.getDocument());
						relatedDocumentsWeights.put(dId, new Integer(WEIGHT_FROM_KEYWORD));
					} else {
						relatedDocumentsWeights.put(dId, relatedDocumentsWeights.get(dId) + new Integer(WEIGHT_FROM_KEYWORD));
					}
				}
			}
			
		} catch (Exception ex) {
			ex.printStackTrace(System.out);
		}
		
		//find related documents based on related categories
		try {
			List<DocumentCategory> relatedCategories = DocumentCategory.findDocumentCategorysByDocument(document).getResultList();
			
			for (DocumentCategory category : relatedCategories) {
				List<DocumentCategory> rDocs = DocumentCategory.findDocumentCategorysByCategory(category.getCategory()).getResultList();
				
				for (DocumentCategory doc : rDocs) {
					if (doc.getDocument().getId() == document.getId()) {
						continue;
					}
					
					String dId = doc.getDocument().getId().toString();
					
					if (! relatedDocuments.containsKey(dId)) {
						relatedDocuments.put(dId, doc.getDocument());
						relatedDocumentsWeights.put(doc.getDocument().getId().toString(), new Integer(WEIGHT_FROM_CATEGORY));
					} else {
						relatedDocumentsWeights.put(doc.getDocument().getId().toString(), relatedDocumentsWeights.get(dId) + new Integer(WEIGHT_FROM_CATEGORY));
					}
				}
			}
			
		}  catch (Exception ex) {
			ex.printStackTrace(System.out);
		}
		
		//log relations to db
		Set<String> dIds = relatedDocuments.keySet();
		
		for (String dId : dIds) {
			//check for existing relationships
			if (doesRelationExist(document, relatedDocuments.get(dId))) {
				lastRelationFound.setWeight(lastRelationFound.getWeight() + relatedDocumentsWeights.get(dId));
				
				lastRelationFound.merge();
			} else {
				lastRelationFound = new DocumentRelatedDocument();
				
				lastRelationFound.setDocument(document);
				lastRelationFound.setRelatedDocument(relatedDocuments.get(dId));
				lastRelationFound.setWeight(relatedDocumentsWeights.get(dId));
				
				lastRelationFound.persist();
			}
			
			//check for existing relationships - backwards
			if (doesRelationExist(relatedDocuments.get(dId), document)) {
				lastRelationFound.setWeight(lastRelationFound.getWeight() + relatedDocumentsWeights.get(dId));
				
				lastRelationFound.merge();
			} else {
				lastRelationFound = new DocumentRelatedDocument();
				
				lastRelationFound.setDocument(relatedDocuments.get(dId));
				lastRelationFound.setRelatedDocument(document);
				lastRelationFound.setWeight(relatedDocumentsWeights.get(dId));
				
				lastRelationFound.persist();
			}
			
		}
	}
	
}
